﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VRacer;
using System.Collections.ObjectModel;
using VRacer.Client.Converters;

namespace VRacer.Controls
{
    /// <summary>
    /// Interaction logic for GameBoard.xaml
    /// </summary>
    public partial class GameBoard : Grid
    {
        public readonly static DependencyProperty GameProperty = DependencyProperty.Register("Game", typeof(Game), typeof(GameBoard), new PropertyMetadata(new PropertyChangedCallback(GameChanged)));

        //protected ObservableCollection<PlayerBase> _players = new ObservableCollection<PlayerBase>();

        private static void GameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Game oldGame = (Game)e.OldValue;
            Game newGame = (Game)e.NewValue;
            (d as GameBoard).GameChanged(oldGame, newGame);
        }

        private void GameChanged(Game oldGame, Game newGame)
        {
            Dispatcher.BeginInvoke((DefaultDelegate)(() =>
                {
                    if (oldGame != null)
                    {
                        oldGame.PropertyChanged -= Game_PropertyChanged;
                    }

                    newGame.PropertyChanged += Game_PropertyChanged;
                }));
        }

        private int _checkSize = 10;

        public GameBoard()
        {
            InitializeComponent();

            var multiplyConverter = new MultiplyConverter();

            this.SetBinding(Grid.WidthProperty, new Binding("Game.CurrentTrack.Width")
            {
                Source = this,
                Converter = multiplyConverter,
                ConverterParameter = "10"
            });

            this.SetBinding(Grid.HeightProperty, new Binding("Game.CurrentTrack.Height")
            {
                Source = this,
                Converter = multiplyConverter,
                ConverterParameter = "10"
            });

            this.MouseLeftButtonDown += Board2_MouseLeftButtonDown;
            this.MouseLeftButtonUp += Board2_MouseLeftButtonUp;
        }

        void Game_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            Dispatcher.BeginInvoke((DefaultDelegate)(() =>
                {
                    if (e.PropertyName == "ActivePlayer")
                        UpdateBigDot(Game.ActivePlayer.ResultantPosition);
                    else if (e.PropertyName == "CurrentTrack")
                    {
                        this.Height = Game.CurrentTrack.Height * CheckSize;
                        this.Width = Game.CurrentTrack.Width * CheckSize;
                    }
                }));
        }

        protected Point GetCheckXY(Point mousePosition)
        {
            var x = (int)(mousePosition.X / CheckSize);
            var y = (int)(mousePosition.Y / CheckSize);
            var xMod = mousePosition.X % CheckSize;
            var yMod = mousePosition.Y % CheckSize;

            if (xMod >= CheckSize / 2)
                x++;

            if (yMod >= CheckSize / 2)
                y++;

            return new Point(x, y);
        }

        #region Events

        bool _isMouseClick = false;
        void Board2_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            _isMouseClick = true;
        }

        void Board2_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (_isMouseClick && Game.ActivePlayer != null)
            {
                Point check = GetCheckXY(e.GetPosition(this));
                Game.ActivePlayer.Move(check);

                _isMouseClick = false;
            }

            Focus();
        }

        #endregion

        #region Overrides
        protected override Size MeasureOverride(Size constraint)
        {
            return base.MeasureOverride(new Size(Game.CurrentTrack.Width * CheckSize, Game.CurrentTrack.Height * CheckSize));
        }

        protected override Size ArrangeOverride(Size arrangeSize)
        {
            return base.ArrangeOverride(new Size(Game.CurrentTrack.Width * CheckSize, Game.CurrentTrack.Height * CheckSize));
        }

        protected override void OnRender(System.Windows.Media.DrawingContext dc)
        {
            base.OnRender(dc);

            dc.DrawRectangle(Brushes.Transparent, new Pen(Brushes.Green, 2), new Rect(0, 0, this.ActualWidth, this.ActualHeight));

            var lineBrush = new SolidColorBrush(Color.FromArgb(127, 0, 0, 0));
            //draw horizontalLines
            for (int i = 0; i <= Game.CurrentTrack.Height; i++)
                dc.DrawLine(new Pen(lineBrush, 1), new Point(0, i * CheckSize), new Point(ActualWidth, i * CheckSize));

            //draw verticalLines
            for (int i = 0; i <= Game.CurrentTrack.Width; i++)
                dc.DrawLine(new Pen(lineBrush, 1), new Point(i * CheckSize, 0), new Point(i * CheckSize, ActualHeight));

        }

        #endregion

        protected int CheckSize
        {
            get { return _checkSize; }
            set { _checkSize = value; }
        }

        public Game Game
        {
            get { return (Game)GetValue(GameProperty); }
            set { SetValue(GameProperty, value); }
        }

        private void Root_KeyUp(object sender, KeyEventArgs e)
        {
            if (Game.ActivePlayer == null)
                return;
            e.Handled = true;

            switch (e.Key)
            {
                case Key.Down:
                    if ((Canvas.GetTop(cursor) - CheckSize) / CheckSize < Game.ActivePlayer.ResultantPosition.Y)
                        Canvas.SetTop(cursor, Canvas.GetTop(cursor) + CheckSize);
                    break;
                case Key.Up:
                    if ((Canvas.GetTop(cursor) + CheckSize) / CheckSize > Game.ActivePlayer.ResultantPosition.Y)
                        Canvas.SetTop(cursor, Canvas.GetTop(cursor) - CheckSize);
                    break;
                case Key.Right:
                    if ((Canvas.GetLeft(cursor) - CheckSize) / CheckSize < Game.ActivePlayer.ResultantPosition.X)
                        Canvas.SetLeft(cursor, Canvas.GetLeft(cursor) + CheckSize);
                    break;
                case Key.Left:
                    if ((Canvas.GetLeft(cursor) + CheckSize) / CheckSize > Game.ActivePlayer.ResultantPosition.X)
                        Canvas.SetLeft(cursor, Canvas.GetLeft(cursor) - CheckSize);
                    break;
                case Key.Enter:
                    Game.ActivePlayer.Move(new Point(Math.Round(Canvas.GetLeft(cursor) / CheckSize), Math.Round(Canvas.GetTop(cursor) / CheckSize)));
                    break;
                default:
                    e.Handled = false;
                    break;
            }
        }

        private void UpdateBigDot(Point point)
        {
            Canvas.SetLeft(cursor, point.X * CheckSize);
            Canvas.SetTop(cursor, point.Y * CheckSize);
            cursor.Fill = Game.ActivePlayer.BrushColor;
        }

        

        private void Root_Loaded(object sender, RoutedEventArgs e)
        {
            Keyboard.Focus(this);
            /*KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Local);
            KeyboardNavigation.SetControlTabNavigation(this, KeyboardNavigationMode.Local);
            KeyboardNavigation.SetAcceptsReturn(this, false);
            KeyboardNavigation.SetTabNavigation(this, KeyboardNavigationMode.Local);
            */
        }
    }
}
